import Util from "../util/util";
import Ball from "./ball";

const { ccclass, property } = cc._decorator;

@ccclass
export default class BallGenerator extends cc.Component {

    private static readonly RANDOM_MAX: number = 4;
    private static readonly BALLSPEED: number = 2000;
    private static readonly FIRE_INTERVAL: number = 150;

    private static ballPool: Ball[] = [];

    private audioSource: cc.AudioSource = null;

    private worldPoint: cc.Vec2;
    private ratioAngle: number;

    private currentBall: Ball = null;
    private fireTimer: number = 0;

    private target: cc.Vec2 = null;

    onLoad(){
        this.audioSource = this.node.getComponent(cc.AudioSource);
    }

    start() {

        this.ratioAngle = 2 * Math.PI / 360;
        this.worldPoint = this.node.convertToWorldSpaceAR(cc.v2());

        if (this.currentBall == null) {
            let _this = this;
            this.getBalldAndSetReady(1, function (ball: Ball) {
                _this.currentBall = ball;
            });
        }
    }

    public fireBall(targetNode: cc.Vec2){
        this.target = targetNode;
        if(this.fireTimer == 0){
            let _this = this;
            _this.fireBallToTarget(_this.target)
            this.fireTimer = setInterval(function(){
                _this.fireBallToTarget(_this.target);
            }, BallGenerator.FIRE_INTERVAL);
        }
    }

    public stopFire(){
        if(this.fireTimer != null){
            clearInterval(this.fireTimer);
            this.fireTimer = 0;
        }
    }

    public fireBallToTarget(targetNode: cc.Vec2) {

        let angle: number = Util.absAngle(this.worldPoint, targetNode);
        let absSpeedX: number = BallGenerator.BALLSPEED * Math.cos(this.ratioAngle * angle);
        let absSpeedY: number = BallGenerator.BALLSPEED * Math.sin(this.ratioAngle * angle);
        let speedX: number = targetNode.x > this.worldPoint.x? absSpeedX: -absSpeedX; 
        let speedY: number = targetNode.y > this.worldPoint.y? absSpeedY: -absSpeedY;
        

        if(this.currentBall != null){
            this.currentBall.go(speedX, speedY);
            if(this.audioSource.isPlaying){
                this.audioSource.stop();
            }
            this.audioSource.play();
        }

        let _this = this;
        this.getRandomBallAndSetReady(function (ball: Ball) {
            _this.currentBall = ball;
        });
    }

    private getBall(getBallCallBack: (ball: Ball) => void) {
        if (BallGenerator.ballPool.length == 0) {
            Ball.create(function (ball) {
                getBallCallBack(ball);
            }, function(ball){
                BallGenerator.ballPool.push(ball);
            });
        }
        else {
            getBallCallBack(BallGenerator.ballPool.pop());
        }
    }

    private getBalldAndSetReady(num: number, callBack: (ball: Ball) => void) {
        let _this = this;
        this.getBall(function (ball: Ball) {
            ball.node.parent = _this.node;
            ball.node.position = cc.v3();
            ball.init(num);
            callBack(ball);
        });
    }

    private getRandomBallAndSetReady(callBack: (ball: Ball) => void) {
        let randomNum: number = Math.ceil(Math.random() * BallGenerator.RANDOM_MAX);
        this.getBalldAndSetReady(randomNum, callBack);
    }

}
